#ifndef ANIMATIONPROPERTY_H
#define ANIMATIONPROPERTY_H

#include "Core/base.h"
#include "Core/timestep.h"
#include <functional>
#include <cmath> 

namespace CC
{
#define PI (3.1415926)

    class Entity;

    enum AnimtionValueType
    {
        AnimtionValueType_None = 0,
        AnimtionValueType_Int,
        AnimtionValueType_Float,
        AnimtionValueType_Float2,
        AnimtionValueType_Float3
    };

    enum AnimtionState
    {
        AnimtionState_Idle = 0,
        AnimtionState_Running
    };

    enum AnimationPlaybackMode
    {
        AnimationPlaybackMode_Normal = 0,
        AnimationPlaybackMode_PingPong
    };

    typedef std::function<void()> AnimationPropertyCallbackFn;
    typedef std::function<void(float v)> AnimationPropertyCallbackFn1;
    typedef std::function<void(float x,float y)> AnimationPropertyCallbackFn2;
    typedef std::function<void(float x, float y, float z)> AnimationPropertyCallbackFn3;

    //user can not delete this class object, Scene can manage it.

    //animationProperty = new CC::AnimationProperty(&camera3d_camera->GetPosition()[0],
    //    { -5.0,-5.0,0.0 }, { 5.0,0.0,5.0 }, 1000.0//,
    //    //[this]() { Sandbox::AnimCallback(); animationProperty->SetDestory(); animationProperty = NULL; }
    //    //[this]() { Sandbox::AnimCallback(); }
    //    //[this]() { Sandbox::AnimCallback(); animationProperty->SetDestory(); }
    //);

    class AnimationProperty
    {
    public:    
        AnimationProperty()
            : m_AnimValueObject(nullptr)
            , m_StartValue(0.0)
            , m_EndValue(0.0)
            , m_StartValueVec2(0.0)
            , m_EndValueVec2(0.0)
            , m_StartValueVec3(0.0)
            , m_EndValueVec3(0.0)
            , m_CurrentValue(0.0)
            , m_CurrentValueVec2(0.0)
            , m_CurrentValueVec3(0.0)
            , m_AnimTime(0.0)
            , m_AnimtionState(AnimtionState_Idle)
            , m_IsDestory(false)
            , m_AutoDestory(false)
            , m_AnimtionValueType(AnimtionValueType_Float)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(m_AnimValueObject, "value is NULL\n");
        }

        AnimationProperty(float* value) 
            :m_AnimValueObject(value)
            , m_StartValue(0.0)
            , m_EndValue(0.0)
            , m_StartValueVec2(0.0)
            , m_EndValueVec2(0.0)
            , m_StartValueVec3(0.0)
            , m_EndValueVec3(0.0)
            , m_CurrentValue(0.0)
            , m_CurrentValueVec2(0.0)
            , m_CurrentValueVec3(0.0)
            , m_AnimTime(0.0)
            , m_AnimtionState(AnimtionState_Idle)
            , m_IsDestory(false)
            , m_AutoDestory(false)
            , m_AnimtionValueType(AnimtionValueType_Float)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {

        }
        AnimationProperty(float* value, float startValue, float endValue, float animTime, bool autodestory = false)
            :m_AnimValueObject(value)
            , m_StartValue(startValue)
            , m_EndValue(endValue)
            , m_StartValueVec2(0.0)
            , m_EndValueVec2(0.0)
            , m_StartValueVec3(0.0)
            , m_EndValueVec3(0.0)
            , m_CurrentValue(startValue)
            , m_CurrentValueVec2(0.0)
            , m_CurrentValueVec3(0.0)
            , m_AnimTime(animTime)
            , m_AnimtionState(AnimtionState_Idle)
            , m_IsDestory(false)
            , m_AutoDestory(autodestory)
            , m_AnimtionValueType(AnimtionValueType_Float)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(value, "value is NULL\n");
            CC_ASSERT(animTime, "animTime is 0\n");
        }

        //animTime unit=ms
        AnimationProperty(float* value, float startValue, float endValue, float animTime, AnimationPropertyCallbackFn1 callbackfn, bool autodestory = false)
            :m_AnimValueObject(value)
            , m_StartValue(startValue)
            , m_EndValue(endValue)
            , m_StartValueVec2(0.0)
            , m_EndValueVec2(0.0)
            , m_StartValueVec3(0.0)
            , m_EndValueVec3(0.0)
            , m_CurrentValue(startValue)
            , m_CurrentValueVec2(0.0)
            , m_CurrentValueVec3(0.0)
            , m_AnimTime(animTime)
            , m_AnimtionState(AnimtionState_Idle)
            , m_AnimationPropertyCallbackFn1(std::move(callbackfn))
            , m_IsDestory(false)
            , m_AutoDestory(autodestory)
            , m_AnimtionValueType(AnimtionValueType_Float)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(value, "value is NULL\n");
            CC_ASSERT(animTime, "animTime is 0\n");
        }

        //animTime unit=ms
        AnimationProperty(float* value, glm::vec2 startValue, glm::vec2 endValue, float animTime, bool autodestory = false)
            :m_AnimValueObject(value)
            , m_StartValue(0.0)
            , m_EndValue(0.0)
            , m_StartValueVec3(0.0)
            , m_EndValueVec3(0.0)
            , m_StartValueVec2(startValue)
            , m_EndValueVec2(endValue)
            , m_CurrentValueVec2(startValue)
            , m_CurrentValue(0.0)
            , m_CurrentValueVec3(0.0)
            , m_AnimTime(animTime)
            , m_AnimtionState(AnimtionState_Idle)
            , m_IsDestory(false)
            , m_AutoDestory(autodestory)
            , m_AnimtionValueType(AnimtionValueType_Float2)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(value, "value is NULL\n");
            CC_ASSERT(animTime, "animTime is 0\n");
        }

        //animTime unit=ms
        AnimationProperty(float* value, glm::vec2 startValue, glm::vec2 endValue, float animTime, AnimationPropertyCallbackFn2 callbackfn, bool autodestory = false)
            :m_AnimValueObject(value)
            , m_StartValue(0.0)
            , m_EndValue(0.0)
            , m_StartValueVec3(0.0)
            , m_EndValueVec3(0.0)
            , m_StartValueVec2(startValue)
            , m_EndValueVec2(endValue)
            , m_CurrentValueVec2(startValue)
            , m_CurrentValue(0.0)
            , m_CurrentValueVec3(0.0)
            , m_AnimTime(animTime)
            , m_AnimtionState(AnimtionState_Idle)
            , m_AnimationPropertyCallbackFn2(std::move(callbackfn))
            , m_IsDestory(false)
            , m_AutoDestory(autodestory)
            , m_AnimtionValueType(AnimtionValueType_Float2)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(value, "value is NULL\n");
            CC_ASSERT(animTime, "animTime is 0\n");
        }

        //animTime unit=ms
        AnimationProperty(float* value, glm::vec3 startValue, glm::vec3 endValue, float animTime, bool autodestory = false)
            :m_AnimValueObject(value)
            , m_StartValue(0.0)
            , m_EndValue(0.0)
            , m_StartValueVec2(0.0)
            , m_EndValueVec2(0.0)
            , m_StartValueVec3(startValue)
            , m_EndValueVec3(endValue)
            , m_CurrentValueVec3(startValue)
            , m_CurrentValueVec2(0.0)
            , m_CurrentValue(0.0)
            , m_AnimTime(animTime)
            , m_AnimtionState(AnimtionState_Idle)
            , m_IsDestory(false)
            , m_AutoDestory(autodestory)
            , m_AnimtionValueType(AnimtionValueType_Float3)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(value, "value is NULL\n");
            CC_ASSERT(animTime, "animTime is 0\n");
        }

        //animTime unit=ms
        AnimationProperty(float* value, glm::vec3 startValue, glm::vec3 endValue, float animTime, AnimationPropertyCallbackFn3 callbackfn, bool autodestory=false)
            :m_AnimValueObject(value)
            , m_StartValue(0.0)
            , m_EndValue(0.0)
            , m_StartValueVec2(0.0)
            , m_EndValueVec2(0.0)
            , m_StartValueVec3(startValue)
            , m_EndValueVec3(endValue)
            , m_CurrentValueVec3(startValue)
            , m_CurrentValueVec2(0.0)
            , m_CurrentValue(0.0)
            , m_AnimTime(animTime)
            , m_AnimtionState(AnimtionState_Idle)
            , m_AnimationPropertyCallbackFn3(std::move(callbackfn))
            , m_IsDestory(false)
            , m_AutoDestory(autodestory)
            , m_AnimtionValueType(AnimtionValueType_Float3)
            , m_CurrentAnimTime(0.0)
            , m_Repeat(false)
            , m_PlaybackMode(AnimationPlaybackMode_Normal)
        {
            CC_ASSERT(value, "value is NULL\n");
            CC_ASSERT(animTime, "animTime is 0\n");
        }

        virtual ~AnimationProperty() {}

        virtual void Update(Timestep ts) = 0;

        virtual void OnEvent(Event &e) {

        }

        virtual void Init(){
        }

        virtual void Start(){   
            m_CurrentAnimTime = 0.0;
            m_CurrentValue = m_StartValue;
            m_CurrentValueVec2 = m_StartValueVec2;
            m_CurrentValueVec3 = m_StartValueVec3;
            m_AnimtionState = AnimtionState_Running;
        }

        virtual void Restart() {
            m_CurrentAnimTime = 0.0;
            m_CurrentValue = m_StartValue;
            m_CurrentValueVec2 = m_StartValueVec2;
            m_CurrentValueVec3 = m_StartValueVec3;
            m_AnimtionState = AnimtionState_Running;
        }

        virtual void Stop(){
            m_AnimtionState = AnimtionState_Idle;
            m_IsDestory = m_AutoDestory;

            if(m_AnimationPropertyCallbackFn){
                m_AnimationPropertyCallbackFn();
            }
            if (m_AnimationPropertyCallbackFn1) {
                m_AnimationPropertyCallbackFn1(m_CurrentValue);
            }
            if (m_AnimationPropertyCallbackFn2) {
                m_AnimationPropertyCallbackFn2(m_EndValueVec2[0], m_EndValueVec2[1]);
            }
            if (m_AnimationPropertyCallbackFn3) {
                m_AnimationPropertyCallbackFn3(m_EndValueVec3[0], m_EndValueVec3[1], m_EndValueVec3[2]);
            }
            
        }

        virtual void SetStartValue(float value) {
            m_StartValue = value;
        }

        virtual void SetStartValue(glm::vec2 value) {
            m_StartValueVec2 = value;
        }

        virtual void SetStartValue(glm::vec3 value) {
            m_StartValueVec3 = value;
        }

        virtual void SetEndValue(float value) {
            m_EndValue = value;
        }

        virtual void SetEndValue(glm::vec2 value) {
            m_EndValueVec2 = value;
        }

        virtual void SetEndValue(glm::vec3 value) {
            m_EndValueVec3 = value;
        }

        virtual void SetAnimTime(float value) {
            m_AnimTime = value;
        }

        virtual void SetRepeat(bool repeat) {
            m_Repeat = repeat;
        }

        virtual void SetPlayBackMode(AnimationPlaybackMode mode) {
            m_PlaybackMode = mode;
        }

        virtual float GetCurrentValue() { return m_CurrentValue; }
        virtual glm::vec2 GetCurrentValueVec2() { return m_CurrentValueVec2; }
        virtual glm::vec3 GetCurrentValueVec3() { return m_CurrentValueVec3; }

        virtual void SetDestory() {
            m_IsDestory = true;
        }

        AnimtionState GetState() {
            return m_AnimtionState;
        };

        bool IsDestory() {
            return m_IsDestory;
        }

        Entity *node = nullptr;
        bool isInit = false;
        
        AnimtionState m_AnimtionState;
        AnimationPropertyCallbackFn m_AnimationPropertyCallbackFn;
        AnimationPropertyCallbackFn1 m_AnimationPropertyCallbackFn1;
        AnimationPropertyCallbackFn2 m_AnimationPropertyCallbackFn2;
        AnimationPropertyCallbackFn3 m_AnimationPropertyCallbackFn3;
        bool m_IsDestory;
        bool m_AutoDestory;
        bool m_Repeat;
        AnimationPlaybackMode m_PlaybackMode;

        AnimtionValueType m_AnimtionValueType;
        float* m_AnimValueObject;
        float m_StartValue;
        float m_EndValue;
        float m_CurrentValue;

        glm::vec2 m_StartValueVec2;
        glm::vec2 m_EndValueVec2;
        glm::vec2 m_CurrentValueVec2;

        glm::vec3 m_StartValueVec3;
        glm::vec3 m_EndValueVec3;
        glm::vec3 m_CurrentValueVec3;

        float m_AnimTime;
        float m_CurrentAnimTime;

    };

    class AnimationPropertyLinear: public AnimationProperty
    {
    public:
        AnimationPropertyLinear() : AnimationProperty(nullptr) {}
        //animTime unit=ms
        AnimationPropertyLinear(float* value)
            :AnimationProperty(value)
        {
        }
        //animTime unit=ms
        AnimationPropertyLinear(float* value, float startValue, float endValue, float animTime, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, autodestory)
        {
        }

        AnimationPropertyLinear(float* value, float startValue, float endValue, float animTime, AnimationPropertyCallbackFn1 callbackfn, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, callbackfn, autodestory)
        {
        }

        AnimationPropertyLinear(float* value, glm::vec2 startValue, glm::vec2 endValue, float animTime, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, autodestory)
        {
        }

        AnimationPropertyLinear(float* value, glm::vec2 startValue, glm::vec2 endValue, float animTime, AnimationPropertyCallbackFn2 callbackfn, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, callbackfn, autodestory)
        {
        }

        AnimationPropertyLinear(float* value, glm::vec3 startValue, glm::vec3 endValue, float animTime, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, autodestory)
        {
        }

        AnimationPropertyLinear(float* value, glm::vec3 startValue, glm::vec3 endValue, float animTime, AnimationPropertyCallbackFn3 callbackfn, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, callbackfn, autodestory)
        {
        }

        virtual ~AnimationPropertyLinear() {}

        virtual void Update(Timestep ts) {

            if (AnimtionState_Running == m_AnimtionState) {

                m_CurrentAnimTime += ts.GetMilliseconds();
                float radio = m_CurrentAnimTime / m_AnimTime;
                radio = radio > 1.0 ? 1.0 : radio;


                if (AnimtionValueType_Float == m_AnimtionValueType) {
                    m_CurrentValue = (m_EndValue - m_StartValue) * radio + m_StartValue;
                    *m_AnimValueObject = m_CurrentValue;

                    //CC_CORE_INFO("AnimationProperty update %f %f %f %f,%f\n", m_StartValue, m_EndValue, m_AnimTime, speed, ts.GetMilliseconds());
                }
                else if (AnimtionValueType_Float2 == m_AnimtionValueType) {
                    m_CurrentValueVec2[0] = (m_EndValueVec2[0] - m_StartValueVec2[0]) * radio + m_StartValueVec2[0];
                    m_CurrentValueVec2[1] = (m_EndValueVec2[1] - m_StartValueVec2[1]) * radio + m_StartValueVec2[1];

                    m_AnimValueObject[0] = m_CurrentValueVec2[0];
                    m_AnimValueObject[1] = m_CurrentValueVec2[1];

                    //CC_CORE_INFO("AnimationProperty update %f %f %f %f,%f\n", m_StartValue, m_EndValue, m_AnimTime, speed, ts.GetMilliseconds());
                }
                else if (AnimtionValueType_Float3 == m_AnimtionValueType) {
                    //float length = glm::length(m_EndValueVec3 - m_StartValueVec3);

                    m_CurrentValueVec3[0] = (m_EndValueVec3[0] - m_StartValueVec3[0]) * radio + m_StartValueVec3[0];
                    m_CurrentValueVec3[1] = (m_EndValueVec3[1] - m_StartValueVec3[1]) * radio + m_StartValueVec3[1];
                    m_CurrentValueVec3[2] = (m_EndValueVec3[2] - m_StartValueVec3[2]) * radio + m_StartValueVec3[2];

                    m_AnimValueObject[0] = m_CurrentValueVec3[0];
                    m_AnimValueObject[1] = m_CurrentValueVec3[1];
                    m_AnimValueObject[2] = m_CurrentValueVec3[2];

                    //CC_CORE_INFO("AnimationProperty update %f %f %f %f,%f\n", m_StartValue, m_EndValue, m_AnimTime, speed, ts.GetMilliseconds());
                }

                if (m_CurrentAnimTime >= m_AnimTime) {
                    if (m_Repeat) {
                        if (AnimationPlaybackMode_Normal == m_PlaybackMode) {
                            
                        }
                        else if (AnimationPlaybackMode_PingPong == m_PlaybackMode) {
                            float startvalue = m_StartValue;
                            SetStartValue(m_EndValue);
                            SetEndValue(startvalue);

                            glm::vec2 startValueVec2 = m_StartValueVec2;
                            SetStartValue(m_EndValueVec2);
                            SetEndValue(startValueVec2);

                            glm::vec2 startValueVec3 = m_StartValueVec3;
                            SetStartValue(m_EndValueVec3);
                            SetEndValue(startValueVec3);
                        }
                        
                        Start();
                    }
                    else {
                        Stop();
                    }                    
                }
            }            
        }
    };

    class AnimationPropertyEaseOutSine : public AnimationProperty
    {
    public:
        AnimationPropertyEaseOutSine() : AnimationProperty(nullptr) {}
        //animTime unit=ms
        AnimationPropertyEaseOutSine(float* value)
            :AnimationProperty(value)
        {
        }
        //animTime unit=ms
        AnimationPropertyEaseOutSine(float* value, float startValue, float endValue, float animTime, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, autodestory)
        {
        }

        AnimationPropertyEaseOutSine(float* value, float startValue, float endValue, float animTime, AnimationPropertyCallbackFn1 callbackfn, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, callbackfn, autodestory)
        {
        }

        AnimationPropertyEaseOutSine(float* value, glm::vec2 startValue, glm::vec2 endValue, float animTime, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, autodestory)
        {
        }

        AnimationPropertyEaseOutSine(float* value, glm::vec2 startValue, glm::vec2 endValue, float animTime, AnimationPropertyCallbackFn2 callbackfn, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, callbackfn, autodestory)
        {
        }

        AnimationPropertyEaseOutSine(float* value, glm::vec3 startValue, glm::vec3 endValue, float animTime, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, autodestory)
        {
        }

        AnimationPropertyEaseOutSine(float* value, glm::vec3 startValue, glm::vec3 endValue, float animTime, AnimationPropertyCallbackFn3 callbackfn, bool autodestory = false)
            :AnimationProperty(value, startValue, endValue, animTime, callbackfn, autodestory)
        {
        }

        virtual ~AnimationPropertyEaseOutSine() {}

        virtual void Update(Timestep ts) {

            if (AnimtionState_Running == m_AnimtionState) {

                m_CurrentAnimTime += ts.GetMilliseconds();
                float radio = m_CurrentAnimTime / m_AnimTime;
                radio = radio > 1.0 ? 1.0 : radio;

                if (AnimtionValueType_Float == m_AnimtionValueType) {
                    m_CurrentValue = (m_EndValue - m_StartValue) * std::sin(radio * (PI / 2.0)) + m_StartValue;
                    *m_AnimValueObject = m_CurrentValue;

                    //CC_CORE_INFO("AnimationProperty update %f %f %f %f,%f\n", m_StartValue, m_EndValue, m_AnimTime, speed, ts.GetMilliseconds());
                }
                else if (AnimtionValueType_Float2 == m_AnimtionValueType) {
                    float radioSin = std::sin(radio * (PI / 2.0));

                    m_CurrentValueVec2[0] = (m_EndValueVec2[0] - m_StartValueVec2[0]) * radioSin + m_StartValueVec2[0];
                    m_CurrentValueVec2[1] = (m_EndValueVec2[1] - m_StartValueVec2[1]) * radioSin + m_StartValueVec2[1];

                    m_AnimValueObject[0] = m_CurrentValueVec2[0];
                    m_AnimValueObject[1] = m_CurrentValueVec2[1];

                    //CC_CORE_INFO("AnimationProperty update %f %f %f %f,%f\n", m_StartValue, m_EndValue, m_AnimTime, speed, ts.GetMilliseconds());
                }
                else if (AnimtionValueType_Float3 == m_AnimtionValueType) {
                    float radioSin = std::sin(radio * (PI / 2.0));

                    m_CurrentValueVec3[0] = (m_EndValueVec3[0] - m_StartValueVec3[0]) * radioSin + m_StartValueVec3[0];
                    m_CurrentValueVec3[1] = (m_EndValueVec3[1] - m_StartValueVec3[1]) * radioSin + m_StartValueVec3[1];
                    m_CurrentValueVec3[2] = (m_EndValueVec3[2] - m_StartValueVec3[2]) * radioSin + m_StartValueVec3[2];

                    m_AnimValueObject[0] = m_CurrentValueVec3[0];
                    m_AnimValueObject[1] = m_CurrentValueVec3[1];
                    m_AnimValueObject[2] = m_CurrentValueVec3[2];

                    //CC_CORE_INFO("AnimationProperty update %f %f %f %f,%f\n", m_StartValue, m_EndValue, m_AnimTime, speed, ts.GetMilliseconds());
                }
                if (m_CurrentAnimTime >= m_AnimTime) {
                    if (m_Repeat) {
                        if (AnimationPlaybackMode_Normal == m_PlaybackMode) {
                        }
                        else if (AnimationPlaybackMode_PingPong == m_PlaybackMode) {
                            float startvalue = m_StartValue;
                            SetStartValue(m_EndValue);
                            SetEndValue(startvalue);

                            glm::vec2 startValueVec2 = m_StartValueVec2;
                            SetStartValue(m_EndValueVec2);
                            SetEndValue(startValueVec2);

                            glm::vec2 startValueVec3 = m_StartValueVec3;
                            SetStartValue(m_EndValueVec3);
                            SetEndValue(startValueVec3);
                        }
                        Start();
                    }
                    else {
                        Stop();
                    }
                }
            }

        }
        
    };

    class AnimationPropertyPause : public AnimationProperty
    {
    public:
        AnimationPropertyPause() : AnimationProperty(nullptr) {}
        AnimationPropertyPause(float animTime) : AnimationProperty(nullptr) {
            AnimationProperty::SetAnimTime(animTime);
        }

        virtual ~AnimationPropertyPause() {}

        virtual void Update(Timestep ts) {
            if (AnimtionState_Running == m_AnimtionState) {
                m_CurrentAnimTime += ts.GetMilliseconds();
                if (m_CurrentAnimTime >= m_AnimTime) {
                    Stop();
                }
            }
        }
    };

    class AnimationPropertyGroup
    {
    public:
        AnimationPropertyGroup()
            :m_AnimtionState(AnimtionState_Idle)
        , m_Repeat(false)
        , m_PlaybackMode(AnimationPlaybackMode_Normal) {}

        ~AnimationPropertyGroup() {
            Clear();
        }

        void AddAnimationProperty(AnimationProperty* a) {
            m_groups.push_back(a);
            m_groupLen = m_groups.size();
        }

        AnimationProperty* GetAnimationProperty(int index) {
            CC_ASSERT(index < m_groupLen, "GetAnimationProperty index(%d) >= m_groupLen(%d)", index, m_groupLen);
            return m_groups[index];
        }

        void Clear() {
            for (auto a : m_groups) {
                delete a;
            }
            m_groups.clear();
            m_groupLen = 0;
        }

        virtual void Update(Timestep ts) {
            if (AnimtionState_Running == m_AnimtionState) {
                if (m_AnimIndex < m_groupLen) {
                    auto& anim = m_groups[m_AnimIndex];

                    if (anim->GetState() == AnimtionState_Idle) {
                        anim->Restart();
                    }

                    anim->Update(ts);

                    if (anim->GetState() == AnimtionState_Idle) {
                        bool end = false;
                        if (AnimationPlaybackMode_Normal == m_PlaybackMode) {
                            m_AnimIndex++;
                            end = m_AnimIndex >= m_groupLen;
                        }
                        else if (AnimationPlaybackMode_PingPong == m_PlaybackMode) {
                            //todo
                            //m_AnimIndex--;
                            //end = m_AnimIndex < 0;
                        }

                        if (end) {
                            if (m_Repeat) {
                                if (AnimationPlaybackMode_Normal == m_PlaybackMode) {
                                    m_AnimIndex = 0.0;
                                }
                                else if (AnimationPlaybackMode_PingPong == m_PlaybackMode) {
                                    //todo
                                    //m_AnimIndex = m_groupLen - 1;
                                }

                                m_AnimtionState = AnimtionState_Running;
                            }
                            else {
                                Stop();
                            }
                        }
                    }
                }
                else {
                    Stop();
                }
            }
            
        }

        virtual void Start() {
            m_AnimIndex = 0.0;
            m_AnimtionState = AnimtionState_Running;
        }

        virtual void Restart() {
            m_AnimIndex = 0.0;
            m_AnimtionState = AnimtionState_Running;
        }

        virtual void Stop() {
            m_AnimtionState = AnimtionState_Idle;
        }

        virtual void SetRepeat(bool repeat) {
            m_Repeat = repeat;
        }

        virtual void SetPlayBackMode(AnimationPlaybackMode mode) {
            m_PlaybackMode = mode;
        }

        AnimtionState GetState() {
            return m_AnimtionState;
        };

        int m_AnimIndex = 0;
        AnimtionState m_AnimtionState;
        bool m_Repeat;
        AnimationPlaybackMode m_PlaybackMode;

        std::vector<AnimationProperty*> m_groups;
        int m_groupLen = 0;
    };
}

#endif